<?php

class Models_Manga
{
    private static $_instance = null;
    private $_db;
    protected $_image;
    protected $_name;
    protected $_id;
    protected $_active;
    protected $_ord;
    private $_tablename;
    private $_config;

    /**
     *
     * @param array $options            
     */
    public function __construct($options = null)
    {}

    /**
     *
     * @param array $options            
     * @return Models_Manga
     */
    public static function factory($options = null)
    {
        if (! self::$_instance) {
            self::$_instance = new self($options);
        }
        return self::$_instance;
    }

    public function getProductUpdate($from, $to)
    {
        try {
            $sql = "SELECT * from product limit " . $from . "," . $to;
            $result = $this->_db->fetchAll($sql);
            return $result;
        } catch (Exception $e) {
            die($e);
            pr($e->getMessage());
        }
    }

    public function getProductsReize()
    {
        try {
            $sql = "SELECT  
						p.name, p.image	 
						";
            $from = " FROM `product` p  ";
            $where = " WHERE 1 = 1 AND p.image <> '' limit 1";
            // echo $sql . $from . $where . $groupby . $order . $limit;
            $result = $this->_db->fetchAll($sql . $from . $where . $order . $limit);
            return $result;
        } catch (Exception $e) {
            die($e);
            pr($e->getMessage());
        }
    }

    public function updateSEO($id, $seo)
    {
        try {
            $productData['name_seo'] = $seo;
            var_dump($productData);
            echo $id;
            $result = $this->_db->update('product', $productData, "id = " . $id);
            return $result;
        } catch (Exception $e) {
            die($e);
            pr($e->getMessage());
        }
    }

    public function getListMangasDetail(array $options = null)
    {
        try {
            $sql = "SELECT  
						p.name pName,p.author author,p.source_file, p.image pImage,  p.video video, intro pIntro,description pDescription, p.suggest pSuggest ,p.active pActive, p.ord pOrd, counter pCounter,p.hot pHot,rate pRate,ratingCount pRatingCount, p.new pNew, latestUpdate pLatestUpdate,manufacturer,language,p.point pPoint,p.rankbox pRankbox, p.newrankbox pNewrankbox,
						p.id manga_id, category_id, p.created created,p.ord pOrd,p.csm pCsm,
						c.name cName, c.image cImage	 
						";
            $from = " FROM `manga` p  
						LEFT JOIN `manga_category` c ON c.id = p.category_id ";
            $where = " WHERE 1 = 1 ";
            if (! empty($options)) {
                if (! empty($options['id'])) {
                    $where .= " AND p.id = {$this->_db->quote($options['id'], 'INTEGER')} ";
                }
                if (! empty($options['name'])) {
                    $where .= " AND p.name LIKE {$this->_db->quote('%'.$options['name'].'%')}";
                }
                if (! empty($options['category'])) {
                    $where .= " AND category_id = {$this->_db->quote($options['category'], 'INTEGER')} ";
                }
                if (! empty($options['hot'])) {
                    $where .= " AND p.hot = {$this->_db->quote($options['hot'], 'INTEGER')} ";
                }
                if (isset($options['active']) && $options['active'] != 1) {
                    $where .= " AND (p.active = {$this->_db->quote($options['active'], 'INTEGER')} OR p.active <> 0)";
                }
                if (! empty($options['suggest'])) {
                    $where .= " AND p.suggest = {$this->_db->quote($options['suggest'], 'INTEGER')} ";
                }
                if (! empty($options['sort'])) {
                    $order .= " ORDER BY {$options['sort']} ";
                }
            }
            if (! empty($options['from']) || ! empty($options['to'])) {
                $limit .= " LIMIT " . $options['from'] . "," . $options['to'];
            }
            // echo $sql . $from . $where . $groupby . $order . $limit;
            $result = $this->_db->fetchAll($sql . $from . $where . $order . $limit);
            return $result;
        } catch (Exception $e) {
            die($e);
            pr($e->getMessage());
        }
    }

    /**
     * get all category from db
     */
    public function getMangas(array $options = null)
    {
        try {
            $sql = "SELECT *, p.id manga_id,p.category_id as category_id, p.image image,  p.name name, p.intro intro, p.description description,p.active active, p.latestUpdate latestUpdate,p.new new, c.name as cName";
            $from = " FROM `manga` p  
						LEFT JOIN `manga_category` c ON c.id = p.category_id ";
            $where = " WHERE 1 = 1 ";
            if (! empty($options)) {
                if (! empty($options['id'])) {
                    $where .= " AND p.id = {$this->_db->quote($options['id'], 'INTEGER')} ";
                }
                if (! empty($options['name'])) {
                    $where .= " AND p.name LIKE {$this->_db->quote('%'.$options['name'].'%')}";
                }
                if (! empty($options['category'])) {
                    $where .= " AND category_id = {$this->_db->quote($options['category'], 'INTEGER')} ";
                }
                if (! empty($options['hot'])) {
                    $where .= " AND p.hot = {$this->_db->quote($options['hot'], 'INTEGER')} ";
                }
                if (isset($options['active']) && $options['active'] != 2) {
                    $where .= " AND (p.active = {$this->_db->quote($options['active'], 'INTEGER')})";
                }
                if (isset($options['sort'])) {
                    $order .= " ORDER BY {$options['sort']}";
                }
            }
            // $groupby = ' GROUP BY product_id ';
            if (! empty($options['from']) || ! empty($options['to'])) {
                $limit .= " LIMIT " . $options['from'] . "," . $options['to'];
            }
            // prAli($sql . $from . $where . $groupby . $order . $limit);
            $result = $this->_db->fetchAll($sql . $from . $where . $groupby . $order . $limit); // pr($sql.$from.$where.$order);
            return $result;
        } catch (Exception $e) {
            pr($e->getMessage());
        }
    }

    /**
     * get all category from db
     */
    public function getTotalMangas(array $options = null)
    {
        try {
            $sql = "SELECT count(distinct(p.id)) as total ";
            $from = " FROM `manga` p LEFT JOIN `manga_category` c ON c.id = p.category_id ";
            $where = " WHERE 1 = 1 ";
            if (! empty($options)) {
                if (! empty($options['id'])) {
                    $where .= " AND p.id = {$this->_db->quote($options['id'], 'INTEGER')} ";
                }
                if (! empty($options['name'])) {
                    $where .= " AND p.name LIKE {$this->_db->quote('%'.$options['name'].'%')}";
                }
                if (! empty($options['category'])) {
                    $where .= " AND category_id = {$this->_db->quote($options['category'], 'INTEGER')} ";
                }
                if (isset($options['active']) && $options['active'] != 1) {
                    $where .= " AND (p.active = {$this->_db->quote($options['active'], 'INTEGER')} OR p.active <> 0)";
                }
            }
            // prAli($sql . $from . $where . $order . $limit);
            $result = $this->_db->fetchRow($sql . $from . $where . $order . $limit); // pr($sql.$from.$where.$order);
                                                                                     // prAli($result);
            return $result['total'];
        } catch (Exception $e) {
            pr($e->getMessage());
        }
    }

    public function getListMangas(array $options = null)
    {
        try {
            $sql = "SELECT 
						* ";
            $from = " FROM `manga`";
            $where = " WHERE 1 = 1 AND name != '' ";
            $order = " order by name asc ";
            $result = $this->_db->fetchAll($sql . $from . $where . $order); // pr($sql.$from.$where.$order);
            return $result;
        } catch (Exception $e) {
            pr($e->getMessage());
        }
    }

    public function getMaxOrder()
    {
        try {
            $sql = "SELECT MAX(ord) as maxOrder ";
            $from = " FROM `manga_category` ";
            $where = " WHERE 1 = 1 ";
            $result = $this->_db->fetchRow($sql . $from . $where);
            return $result['maxOrder'];
        } catch (Exception $e) {
            pr($e->getMessage());
        }
    }

    public function insertManga($data)
    {
        // Start a transaction explicitly.
        try {
            // Attempt to execute one or more queries:
            $productDetailData = array();
            /* insert table product */
            $productData = array(
                                "id" => null, 
                                "name" => $data['name'], 
                                "name_seo" => $data['name_seo'], 
                                "manufacturer" => $data['manufacturer'], 
                                "language" => $data['language'], 
                                "active" => $data['active'], 
                                "new" => $data['new'], 
                                "intro" => $data['intro'], 
                                "author" => $data['author'], 
                                "description" => $data['description'], 
                                "latestUpdate" => date('Y-m-d H:i:s'), 
                                "category_id" => $data['category_id']
            );
            if (! empty($data['image'])) {
                $productData['image'] = $data['image'];
            }
            if (! empty($data['source_folder'])) {
                $productData['source_folder'] = $data['source_folder'];
                $productData['source_size'] = $data['source_size'];
                $productData['source_hash'] = $data['source_hash'];
            }
            // prAli($productData);
            $this->_db->insert('manga', $productData);
            $result = $this->_db->lastInsertId('manga', 'id');
            // regiter SGN leaderboard if it's point games
        } catch (Exception $e) {
            $this->_db->rollBack();
            pr($e->getMessage());
            die($e);
        }
        return $result;
    }

    public function lastMangaId()
    {
        try {
            $sql = "SELECT MAX(id)";
            $from = " FROM `manga`";
            $result = $this->_db->fetchOne($sql . $from);
            return $result;
        } catch (Exception $exc) {
            prAli($exc->getMessage());
            return - 1;
        }
    }

    public function browseMangas($id)
    {
        $param = array(
                    'id' => $id
        );
        $item = $this->getMangas($param);
        $conn_id = ftp_connect($this->_config->ftp->host);
        $login_result = ftp_login($conn_id, $this->_config->ftp->username, $this->_config->ftp->pwd);
        $directory = $this->_config->ftp->manga_repository . '/' . $item[0]['source_hash'] . '/' . $item[0]['source_folder'];
        $list = ftp_nlist($conn_id, $directory);
        $filter = $this->_config->filter_extension_image;
        $res = array();
        foreach ($list as $file) {
            $fileName = basename($file);
            $ext = substr($fileName, - 3);
            if (preg_match($filter, $ext)) {
                $res[] = $this->_config->imgURL . '/' . $file;
            }
        }
        return $res;
    }

    public function getProductsByCategory(array $options = null, $order = '')
    {
        try {
            $sql = "SELECT DISTINCT p.id, p.name pName,product_id";
            $from = " FROM `product` p INNER JOIN `product_info` pi ON p.id = pi.product_id
						INNER JOIN `category` c ON c.id = pi.category_id";
            $where = " WHERE 1 = 1 ";
            if (! empty($options)) {
                if (! empty($options['category'])) {
                    $where .= " AND category_id = {$this->_db->quote($options['category'], 'INTEGER')} ";
                }
            }
            $result = $this->_db->fetchAll($sql . $from . $where . $order); // pr($sql.$from.$where.$order);
            return $result;
        } catch (Exception $e) {
            pr($e->getMessage());
        }
    }

    public function updateManga($data, $mangaId, $updateVersion = false)
    {
        try {
            /* update table product */
            $productData = array(
                                "name" => $data['name'], 
                                "manufacturer" => $data['manufacturer'], 
                                "language" => $data['language'], 
                                "active" => $data['active'], 
                                "category_id" => $data['category_id'], 
                                "new" => $data['new'], 
                                "name_seo" => $data['name_seo'], 
                                "intro" => $data['intro'], 
                                "author" => $data['author'], 
                                "description" => $data['description'], 
                                "latestUpdate" => date('Y-m-d H:i:s')
            );
            if (! empty($data['image'])) {
                $productData['image'] = $data['image'];
            }
            if (! empty($data['source_folder'])) {
                $productData['source_folder'] = $data['source_folder'];
            }
            if (! empty($data['source_size'])) {
                $productData['source_size'] = $data['source_size'];
            }
            if (! empty($data['source_hash'])) {
                $productData['source_hash'] = $data['source_hash'];
            }
            $result = $this->_db->update('manga', $productData, "id = " . $mangaId);
            // regiter SGN leaderboard if it's point games
            $this->_db->commit();
            return $result;
        } catch (Exception $e) {
            $this->_db->rollBack();
            pr($e->getMessage());
            die($e);
            return 0;
        }
    }

    public function deleteRevision($pvid)
    {
        try {
            $this->_tablename = 'product_version';
            $where = array();
            $where[] = "id = " . $pvid;
            $result = $this->_db->delete($this->_tablename, $where);
            return $result;
        } catch (Exception $e) {
            throw $e;
        }
    }

    public function delete($id)
    {
        // Start a transaction explicitly.
        $this->_db->beginTransaction();
        try {
            $param = array(
                        'id' => $id
            );
            $item = $this->getMangas($param);
            $folder = $item[0]['source_hash'] . '/' . $item[0]['source_folder'];
            $subManga = Models_SubManga::factory();
            $subItems = $subManga->getMangas($param);
            // prAli($subItems);
            foreach ($subItems as $item) {
                $subFolder = $folder . '/' . $item['source_folder'];
                $this->deleteFile($subFolder, true);
                $subManga->delete($id, $item['sub_id']);
            }
            $this->deleteFile($folder, true);
            // delete manga
            $this->_db->delete("manga", "id = {$this->_db->quote($id, 'INTEGER')}");
            // If all succeed, commit the transaction and all changes
            // are committed at once.
            $this->_db->commit();
            return 1;
        } catch (Exception $e) {
            // If any of the queries failed and threw an exception,
            // we want to roll back the whole transaction, reversing
            // changes made in the transaction, even those that succeeded.
            // Thus all changes are committed together, or none are.
            $this->_db->rollBack();
            prAli($e->getMessage());
            return 0;
        }
    }

    public function uncompressZIP($sourceFile, $destination)
    {
        try {
            $zip = new ZipArchive();
            $res = $zip->open($sourceFile);
            if ($res === TRUE) {
                $zip->extractTo($destination);
                $zip->close();
                $dir = scandir($destination);
                $res = array();
                $filter = $this->_config->filter_extension_image;
                foreach ($dir as $file) {
                    $fileName = basename($file);
                    $ext = substr($fileName, - 3);
                    if (preg_match($filter, $ext)) {
                        $res[] = $file;
                    }
                }
                return $res;
            }
        } catch (Exception $exc) {
            prAli($exc->getMessage());
        }
        return false;
    }

    public function uncompressRAR($sourceFile, $destination)
    {
        try {} catch (Exception $exc) {
            prAli($exc->getMessage());
        }
        return false;
    }

    public function deleteFile($folder, $deleteFolder = false)
    {
        try {
            // delete file on server
            $files = glob($folder . '/*'); // get all file names
            foreach ($files as $file) { // iterate files
                if (is_file($file)) {
                    unlink($file); // delete file
                }
            }
            if ($deleteFolder) {
                rmdir($folder);
            }
        } catch (Exception $exc) {
            pr($exc->getMessage());
        }
    }

    public function renameFolder($pathFolder, $newName)
    {
        try {
            // delete file on img
            // $conn_id = ftp_connect($this->_config->ftp->host);
            // $login_result = ftp_login($conn_id,
            // $this->_config->ftp->username, $this->_config->ftp->pwd);
            // $root = $this->_config->ftp->manga_repository;
            if (is_dir($this->_config->destinationUpload . '/' . $pathFolder)) {
                rename($this->_config->destinationUpload . '/' . $pathFolder, $this->_config->destinationUpload . '/' . $newName);
            }
            // ftp_rename($conn_id, $root . '/' . $pathFolder, $root . '/' .
            // $newName);
            return true;
        } catch (Exception $exc) {
            prAli($exc->getMessage());
            return false;
        }
    }

    public function createFolder($folder)
    {
        try {
            if (is_array($folder)) {
                $dir = '';
                for ($i = 0; $i < count($folder); $i ++) {
                    $f = $folder[$i];
                    if ($i > 0) {
                        $dir .= '/';
                    }
                    $dir .= $f;
                    if (! is_dir($dir)) {
                        mkdir($dir);
                    }
                }
            } else {
                if (! is_dir($folder)) {
                    mkdir($folder);
                }
            }
            return true;
        } catch (Exception $exc) {
            prAli($exc->getMessage());
            return false;
        }
    }

    /**
     * Get hash file name
     */
    public function hashAccountName($fileName, $totalTb = 512)
    {
        if (! empty($fileName)) {
            $total = 0;
            $array = str_split($fileName);
            foreach ($array as $char) {
                $total = $total % $totalTb + ord($char);
            }
            $result = sprintf('%04d', $total % $totalTb);
            return $result;
        } else {
            return '';
        }
    }

    public function __get($name)
    {
        $method = 'get' . $name;
        if (('mapper' == $name) || ! method_exists($this, $method)) {
            throw new Exception('Invalid invheader property');
        }
        return $this->$method();
    }
}